Skip to content

fix(scheduler): permit same-repository commit status reads - #2121

Merged
seonghobae merged 2 commits into
mainfrom
fix/scheduler-status-read-2120
Sep 13, 2026
Merged

fix(scheduler): permit same-repository commit status reads#2121
seonghobae merged 2 commits into
mainfrom
fix/scheduler-status-read-2120

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

The required scheduler's same-repository read token lacks commit-status permission, so a private consumer's combined-status GET fails with HTTP 403 before status evaluation. Add statuses: read only to scan-pr-queue, and extend the existing credential contract test to require that exact read-only grant. Token selection, status publication and mutation behavior are unchanged.

Refs #2120. Keep the issue open until a newly loaded central SHA successfully reads statuses on the consumer's current head; local validation is not hosted permission evidence. The consumer head inspected has no .github tree, so no repository-local caller grant is being changed.

Validation: the new assertion failed on 9521b6771; corrected head 1c5c6b7afa841f7a4a999f54d45ef8d504a2d818 passed 452 workflow/credential/status tests with GITHUB_ACTIONS=true. The new assertion also passed with the ordinary local environment. Actionlint workflow validation (-shellcheck= -pyflakes=) and git diff --check passed. A separate read-only agent review found no scope or privilege escalation issue; this is not formal GitHub approval.

Operational evidence, endpoint contract and remaining hosted acceptance are in docs/doctoring/scheduler-status-read-permission.md.

Summary by CodeRabbit

  • 버그 수정

    • 병합 스케줄러가 커밋 상태를 읽을 때 발생하던 권한 오류를 수정했습니다.
    • 스케줄러가 동일 저장소의 상태 정보를 읽기 전용으로 조회할 수 있습니다.
  • 문서

    • 상태 조회 권한 요구사항과 관련 검증 절차를 문서화했습니다.
  • 테스트

    • 스케줄러의 상태 조회 권한이 읽기 전용으로 유지되는지 자동 검증을 추가했습니다.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 74e86d39-fb9b-4c6f-a7d0-39f5b0881238

📥 Commits

Reviewing files that changed from the base of the PR and between fb17ef5 and 1c5c6b7.

📒 Files selected for processing (3)
  • .github/workflows/pr-review-merge-scheduler.yml
  • docs/doctoring/scheduler-status-read-permission.md
  • tests/test_opencode_agent_contract.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

scan-pr-queue 작업에 커밋 상태 읽기 권한을 추가했다. 테스트는 권한 값을 검증한다. 문서는 403 오류 원인과 검증 절차를 기록한다.

Changes

스케줄러 상태 권한

Layer / File(s) Summary
상태 읽기 권한 계약과 검증
.github/workflows/pr-review-merge-scheduler.yml, tests/test_opencode_agent_contract.py, docs/doctoring/scheduler-status-read-permission.md
scan-pr-queuestatuses: read를 추가했다. 테스트는 권한 값을 정확히 검증한다. 문서는 403 오류 원인과 권한 범위 및 검증 절차를 설명한다.

Priority: ➖ Normal

Estimated code review effort: 1 (Trivial) | ~5 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 1c5c6

The scheduler gains the required read-only status access without changing credential selection, status publication, or mutation behavior.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files. (2 skipped: 2 …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 동일 저장소 커밋 상태 읽기 권한을 허용하는 주요 변경 사항을 정확하고 간결하게 설명합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/scheduler-status-read-2120

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Current-head CI diagnosis for 1c5c6b7afa841f7a4a999f54d45ef8d504a2d818 (base fb17ef556f94f673234aa557254ae52779e9a7b0):

  • Hosted coverage, Semgrep, Bandit, dependency audit, Trivy and Scorecard passed. CodeRabbit reported no actionable findings; this is not a required independent approval.
  • CodeQL producer 34700436924, Python job 103572243861, completed analysis and published codeql-dispatch/python=success, then failed only at wake: The workflow run containing this job is already running (HTTP 403). The sibling Actions compatibility rerun succeeded. This matches the existing fix(codeql): serialize exact dispatch wakeups #2056 serialization defect; its current handoff identifies fix(codeql): wake required jobs with the exchanged target app token #2040 as canonical successor. No new wake implementation is needed in this PR.
  • Replacement producer 34701309698 for this exact head/base/required run is already queued. No manual rerun or duplicate dispatch was requested.
  • Noema job 103570303715 failed before healthz: free-pool preflight reported 24 candidates, 16 probed/rejected, zero ready, with HTTP 429 and 404 among rejected routes. It did not review this diff. The free-only policy remains intact.

These failures do not establish a code finding or approval. Required OpenCode/Strix and consumer-private status-read acceptance remain outstanding; no merge or issue resolution is claimed.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head source review for 1c5c6b7afa841f7a4a999f54d45ef8d504a2d818 (COMMENT, not approval): no source-level blocker found. The one-line statuses: read grant is confined to scan-pr-queue; it neither grants status publication nor changes the mutation/App-token path. The exact contract assertion scopes the permission block and requires the sole value read. Runtime Quality, Security, SAST, Python Security, and CodeQL are terminal GREEN. OpenCode run 34700520369 is not a code failure: the sole contextual-orchestrator/orchestrator/free route ended outcome=exhausted model=none, so no formal current-head receipt exists. Keep ordinary merge blocked until a qualifying independent approval/receipt exists; do not bypass or substitute this COMMENT.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

현재 exact head 1c5c6b7afa841f7a4a999f54d45ef8d504a2d818만 대상으로 재검토 바랍니다. 특히 scan-pr-queuestatuses: read가 same-repository combined-status GET에 필요한 최소 read 권한인지, status write/mutation 권한 확대가 없는지, 기존 credential selection/publication semantics가 보존되는지 확인해 주세요. 이전 head의 리뷰·체크 결과는 승인 근거로 전용하지 않습니다.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

expected_head="1c5c6b7afa841f7a4a999f54d45ef8d504a2d818"
base="fb17ef556f94f673234aa557254ae52779e9a7b0"

echo "== Checked-out revision =="
git rev-parse HEAD
git status --short

echo "== Verify requested commits exist and inspect exact diff =="
git cat-file -e "${expected_head}^{commit}"
git cat-file -e "${base}^{commit}"
git diff --check "$base" "$expected_head"
git diff --find-renames --find-copies --unified=80 "$base" "$expected_head" -- \
  .github/workflows/pr-review-merge-scheduler.yml \
  tests/test_opencode_agent_contract.py \
  docs/doctoring/scheduler-status-read-permission.md

echo "== Workflow structure and credential/status call sites =="
ast-grep outline .github/workflows/pr-review-merge-scheduler.yml --items all || true
rg -n -i -C 5 \
  'scan-pr-queue|permissions:|statuses:|commit.?status|combined.?status|/statuses|github-token|token:|gh api|curl |POST|PATCH|PUT|DELETE' \
  .github/workflows/pr-review-merge-scheduler.yml

echo "== Contract test context =="
ast-grep outline tests/test_opencode_agent_contract.py --items all --type function || true
rg -n -C 12 \
  'test_merge_scheduler_uses_escalating_mutation_credentials|scan-pr-queue|statuses|credential|token|status' \
  tests/test_opencode_agent_contract.py

echo "== Repository references to scheduler workflow and status APIs =="
rg -n -i -C 3 \
  'pr-review-merge-scheduler|scan-pr-queue|combined.?status|repos/.*/commits/.*/status|/status(es)?\b|statuses:\s*(write|read)' \
  -g '!docs/doctoring/scheduler-status-read-permission.md' \
  .github tests scripts README.md 2>/dev/null || true

echo "== Inspect parent workflow / reusable-workflow permission context =="
rg -n -C 8 \
  'uses:\s*\./\.github/workflows/pr-review-merge-scheduler\.yml|pr-review-merge-scheduler\.yml|workflow_call:|permissions:' \
  .github/workflows 2>/dev/null || true

Length of output: 202345


🏁 Script executed:

#!/bin/bash
set -euo pipefail

expected_head="1c5c6b7afa841f7a4a999f54d45ef8d504a2d818"
base="fb17ef556f94f673234aa557254ae52779e9a7b0"

printf '%s\n' '== Exact revision identity =='
printf 'HEAD='; git rev-parse HEAD
printf 'requested='; git rev-parse "$expected_head"
printf 'base='; git rev-parse "$base"
git merge-base --is-ancestor "$base" "$expected_head"
printf 'base_is_ancestor=yes\n'

printf '%s\n' '== Exact changed paths and patch =='
git diff --name-status "$base" "$expected_head"
git diff --unified=25 "$base" "$expected_head" -- \
  .github/workflows/pr-review-merge-scheduler.yml \
  tests/test_opencode_agent_contract.py \
  docs/doctoring/scheduler-status-read-permission.md

printf '%s\n' '== Scheduler job: exact permission, token, and mutation context =='
sed -n '93,180p' .github/workflows/pr-review-merge-scheduler.yml
rg -n -C 8 \
  'SCHEDULER_(READ|DISPATCH|MUTATION)_TOKEN|MUTATION_TOKEN_SOURCE|github\.token|PR_REVIEW_MERGE_TOKEN|OPENCODE_APPROVE_TOKEN|opencode_app_token|gh api|gh pr|repository_dispatch|/statuses|/status\b|--method (POST|PATCH|PUT|DELETE)|-X (POST|PATCH|PUT|DELETE)' \
  .github/workflows/pr-review-merge-scheduler.yml

printf '%s\n' '== Read API implementation and credential injection =='
sed -n '1280,1350p' scripts/ci/pr_review_merge_scheduler_core.py
rg -n -C 6 \
  'def gh_api_json|GH_TOKEN|GITHUB_TOKEN|SCHEDULER_READ_TOKEN|SCHEDULER_DISPATCH_TOKEN|SCHEDULER_MUTATION_TOKEN|declared_mutation_token_source' \
  scripts/ci/pr_review_merge_scheduler.py \
  scripts/ci/pr_review_merge_scheduler_core.py

printf '%s\n' '== Test delta and adjacent original credential assertions =='
sed -n '2360,2448p' tests/test_opencode_agent_contract.py

Length of output: 65421


🤖 web_search executed:

GitHub REST API documentation: What fine-grained token permission is required for GET /repos/{owner}/{repo}/commits/{ref}/status (combined commit status), and does the endpoint accept "Commit statuses" read permission?

Length of output: 5082


@seonghobae 재검토를 완료했습니다. 검토 대상은 요청한 exact head 1c5c6b7afa841f7a4a999f54d45ef8d504a2d818뿐입니다. 이전 head의 결과는 사용하지 않았습니다.

결과: actionable finding 없음

  • 현재 checkout은 요청한 exact head와 일치합니다.
  • base fb17ef556f94f673234aa557254ae52779e9a7b0는 해당 head의 조상입니다.
  • exact diff는 scan-pr-queue.permissionsstatuses: read 한 줄만 추가합니다. git diff --check도 통과했습니다.
  • 스케줄러는 GET /repos/{owner}/{repo}/commits/{ref}/status를 사용합니다. 이 combined-status endpoint에는 GitHub의 Commit statuses: read 권한이 필요합니다. 따라서 이 변경은 필요한 최소 status 권한입니다. GitHub REST 문서
  • statuses: write는 추가하지 않았습니다. status publication endpoint, status context, 또는 status mutation 경로도 변경하지 않았습니다.
  • SCHEDULER_READ_TOKEN, SCHEDULER_ACTIONS_TOKEN, SCHEDULER_DISPATCH_TOKEN, mutation token source의 선택 식은 변경되지 않았습니다. 같은 저장소 read는 계속 github.token을 사용합니다. cross-repository read와 기존 mutation credential 선택도 유지됩니다.
  • 계약 테스트는 scan-pr-queue permission block에 statuses가 정확히 한 번 존재하며 값이 read인지 확인합니다.

호스팅 환경의 consumer-private acceptance는 이 정적 검토 범위 밖입니다. 해당 acceptance가 별도로 필요하다는 문서의 조건과도 일치합니다.

⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Infrastructure-exception merge record (operator guideline §11), head 1c5c6b7afa841f7a4a999f54d45ef8d504a2d818 on base main fb17ef556f94f673234aa557254ae52779e9a7b0.

Blocking checks and why they are infrastructure, not this change:

  • noema-review run 34700027422: sidecar preflight rejected 16/16 candidate routes (nvidia_nim/nvidia_nim_sub HTTP 429, ready_count: 0 in contextual-orchestrator-preflight.json) → free-pool capacity outage, no model verdict on this diff.
  • strix run 34700027364: sidecar became healthy after 500 s, then STRIX_PROVIDER_UNAVAILABLE: contextual-orchestrator/orchestrator/free exhausted → same outage.
  • opencode-review run 34702805332: "No validated exact-current-head OpenCode approval was published (model outcome: exhausted)" → same outage.
    None of the three produced a substantive finding against the diff.

Substantive gates that did run and pass on this exact head: required-workflow-bootstrap, scan-pr-queue (×2), coverage-evidence, coverage-source-tree, CodeQL compatibility analysis (actions, python) + codeql-dispatch/actions + codeql-dispatch/python, Semgrep (multi-language) + Semgrep OSS, Bandit, gitleaks, pip-audit, trivy-fs, scorecard, agent-review-runtime-quality.

Substitute verification (independent read-only agent on a fresh worktree of this head): diff is exactly one added line, statuses: read, inside the scan-pr-queue job permissions: block (the workflow's only job; job-level permissions replace the top-level contents: read). Call chain confirmed: pr_review_merge_scheduler_core.py:1336gh_api_json("repos/{repo}/commits/{sha}/status")run_github_read → ambient GH_TOKEN: ${{ github.token }} for same-repository events. Targeted suites 482 passed; full GITHUB_ACTIONS=true python3 -m pytest tests -q -rs → 3039 passed, 1 pre-existing LLVM-19 host-tool skip, 0 warnings; actionlint -shellcheck= -pyflakes= clean. The consumer failure log (late-life-anxiety-reanalysis PR #10, run 34700409505 job 103571043736) prints the effective token permission list matching this job block, so the grant is on the token that made the failing call.

Impact: read-only grant on a same-repository token; no mutation, App, or cross-repository credential change.

Deferred verification, to be re-run after merge: the three sidecar reviews on the next central change, and the consumer's exact-head scan-pr-queue on a newly loaded central SHA (issue #2120 stays open until observed). If that re-run shows a substantive failure attributable to this line, revert this merge.

@seonghobae
seonghobae merged commit 0ad785d into main Sep 13, 2026
45 of 53 checks passed
@seonghobae
seonghobae deleted the fix/scheduler-status-read-2120 branch September 13, 2026 04:22
@github-project-automation github-project-automation Bot moved this from In Progress to Done in naruon Platform Roadmap Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant