From 25efbca56f5749cf99f3a5d532070c1b01c6c79d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 07:08:19 +0900 Subject: [PATCH 1/3] fix: grant hourly scheduler OIDC permission --- .github/workflows/disksage-hourly-review-repair.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/disksage-hourly-review-repair.yml b/.github/workflows/disksage-hourly-review-repair.yml index d1868bc20..8624fcd8a 100644 --- a/.github/workflows/disksage-hourly-review-repair.yml +++ b/.github/workflows/disksage-hourly-review-repair.yml @@ -13,6 +13,7 @@ concurrency: permissions: contents: read + id-token: write jobs: dispatch-review-repair: From f75ddc8dd1fa4ea9a4689d2f93232c95e4707afd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 15:18:08 -0700 Subject: [PATCH 2/3] test(disksage): require OIDC caller documentation --- tests/test_disksage_hourly_review_caller.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_disksage_hourly_review_caller.py b/tests/test_disksage_hourly_review_caller.py index bee0d859b..bce9e4081 100644 --- a/tests/test_disksage_hourly_review_caller.py +++ b/tests/test_disksage_hourly_review_caller.py @@ -28,12 +28,12 @@ def test_disksage_caller_is_hourly_bounded_and_non_cancelling() -> None: assert 'retry_hours: "2"' in caller -def test_disksage_caller_preserves_credentials_and_read_only_token_scope() -> None: - """The queue scanner maps established credentials without exposing model secrets.""" +def test_disksage_caller_preserves_credentials_and_oidc_token_scope() -> None: + """The caller grants only read access plus the scheduler's OIDC exchange scope.""" caller = _read(CALLER) workflow_scope, jobs_scope = caller.split("\njobs:\n", maxsplit=1) - assert "\npermissions:\n contents: read\n" in workflow_scope + assert "\npermissions:\n contents: read\n id-token: write\n" in workflow_scope assert "\n permissions:\n" not in jobs_scope assert "PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }}" in caller assert "OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }}" in caller @@ -62,6 +62,8 @@ def test_disksage_caller_doctoring_records_rca_feasibility_and_latency() -> None "NVIDIA_NIM_API_KEY", "COPILOT_GITHUB_TOKEN", "ContextualWisdomLab/disksage", + "`id-token: write`", + "OIDC token exchange", "APA 7th references", ): assert phrase in doctoring From ec090ac045ace6a92206348f13221cd73d3b90d2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 15:19:20 -0700 Subject: [PATCH 3/3] docs(disksage): record OIDC exchange permission --- docs/doctoring/disksage-hourly-review-caller.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/doctoring/disksage-hourly-review-caller.md b/docs/doctoring/disksage-hourly-review-caller.md index 2e30aee8d..5d77dc42d 100644 --- a/docs/doctoring/disksage-hourly-review-caller.md +++ b/docs/doctoring/disksage-hourly-review-caller.md @@ -61,7 +61,10 @@ controls every mutation and merge decision. ## Credential and model boundary -The queue-scanning caller has only `contents: read`. It maps only the established +The queue-scanning caller grants `contents: read` plus `id-token: write`. The +latter is limited to the central scheduler's OpenCode OIDC token exchange and +does not grant repository content, issue, pull-request, status, approval, merge, +or release write authority. The caller maps only the established `PR_REVIEW_MERGE_TOKEN` and `OPENCODE_APPROVE_TOKEN` scheduler credentials and does not use `secrets: inherit`. @@ -88,8 +91,9 @@ neutral-required, stale-head, or synthetic-merge evidence is not success. ## Verification and rollback Repository contracts require the exact cron, target repository, one-dispatch -budget, two-hour retry floor, non-cancelling single-flight policy, read-only -workflow token, explicit secret mapping, and absence of both +budget, two-hour retry floor, non-cancelling single-flight policy, the +least-privilege workflow token (`contents: read` plus OIDC-only +`id-token: write`), explicit secret mapping, and absence of both `NVIDIA_NIM_API_KEY` and `COPILOT_GITHUB_TOKEN` from the caller. Rollback is a reviewed source change. Do not disable exact-head binding, reduce