From 5f8d748549309b8962a1e5d42a86c9ad546442c6 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 16 Aug 2026 16:12:05 +0000 Subject: [PATCH 1/7] ci: switch local OpenCode from GitHub Models to NVIDIA NIM ContextualWisdomLab no longer uses GitHub Models. Point opencode.jsonc at nvidia-nim only, with NVIDIA_API_KEY and the Nemotron Super default. Co-authored-by: Seongho Bae --- opencode.jsonc | 60 ++++++------------- .../tests/test_supply_chain_policy.py | 30 ++++++++-- 2 files changed, 44 insertions(+), 46 deletions(-) diff --git a/opencode.jsonc b/opencode.jsonc index 888aa2375..eeca34f1b 100644 --- a/opencode.jsonc +++ b/opencode.jsonc @@ -1,8 +1,8 @@ { "$schema": "https://opencode.ai/config.json", - "model": "github-models/openai/gpt-5", - "small_model": "github-models/deepseek/deepseek-v3-0324", - "enabled_providers": ["github-models"], + "model": "nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5", + "small_model": "nvidia-nim/meta/llama-3.3-70b-instruct", + "enabled_providers": ["nvidia-nim"], "mcp": { "codegraph": { "type": "local", @@ -37,56 +37,32 @@ } }, "provider": { - "github-models": { + "nvidia-nim": { "npm": "@ai-sdk/openai-compatible", - "name": "GitHub Models", + "name": "NVIDIA NIM", "options": { - "baseURL": "https://models.github.ai/inference", - "apiKey": "{env:STRIX_GITHUB_MODELS_TOKEN}" + "baseURL": "https://integrate.api.nvidia.com/v1", + "apiKey": "{env:NVIDIA_API_KEY}" }, "models": { - "openai/gpt-5": { - "name": "OpenAI GPT-5", + "nvidia/llama-3.3-nemotron-super-49b-v1.5": { + "name": "NVIDIA Llama 3.3 Nemotron Super 49B v1.5", "tool_call": true, "reasoning": true, + "options": { + "reasoningEffort": "high" + }, "limit": { - "context": 200000, - "output": 100000 + "context": 131072, + "output": 32768 } }, - "deepseek/deepseek-r1-0528": { - "name": "DeepSeek R1 0528", + "meta/llama-3.3-70b-instruct": { + "name": "Meta Llama 3.3 70B Instruct", "tool_call": true, - "reasoning": true, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "deepseek/deepseek-v3-0324": { - "name": "DeepSeek V3 0324", - "tool_call": true, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "openai/o3": { - "name": "OpenAI o3", - "tool_call": true, - "reasoning": true, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "openai/o4-mini": { - "name": "OpenAI o4-mini", - "tool_call": true, - "reasoning": true, "limit": { - "context": 200000, - "output": 100000 + "context": 131072, + "output": 16384 } } } diff --git a/services/analysis-engine/tests/test_supply_chain_policy.py b/services/analysis-engine/tests/test_supply_chain_policy.py index ab43df89f..df27f41df 100644 --- a/services/analysis-engine/tests/test_supply_chain_policy.py +++ b/services/analysis-engine/tests/test_supply_chain_policy.py @@ -5073,14 +5073,36 @@ def test_opencode_approval_write_failure_updates_overview_only() -> None: assert "source-backed repository findings" in policy +def test_opencode_uses_nvidia_nim_only() -> None: + """Ensure local OpenCode is NVIDIA NIM only and does not use GitHub Models.""" + repo_root = Path(__file__).resolve().parents[3] + opencode_text = (repo_root / "opencode.jsonc").read_text(encoding="utf-8") + opencode_config = json.loads(opencode_text) + + assert opencode_config["model"] == "nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5" + assert opencode_config["enabled_providers"] == ["nvidia-nim"] + assert set(opencode_config["provider"]) == {"nvidia-nim"} + + nim_provider = opencode_config["provider"]["nvidia-nim"] + assert nim_provider["options"]["baseURL"] == "https://integrate.api.nvidia.com/v1" + assert nim_provider["options"]["apiKey"] == "{env:NVIDIA_API_KEY}" + assert "nvidia/llama-3.3-nemotron-super-49b-v1.5" in nim_provider["models"] + + leftover_tokens = ( + "github-models", + "STRIX_GITHUB_MODELS_TOKEN", + "COPILOT_GITHUB_TOKEN", + "openai/gpt-5", + "models.github.ai", + ) + for leftover in leftover_tokens: + assert leftover not in opencode_text + + def test_pr_review_merge_scheduler_uses_central_mutation_credential() -> None: """Ensure mechanical PR queue handling uses the central mutation credential.""" - repo_root = Path(__file__).resolve().parents[3] policy = central_required_workflow_policy_text() - opencode_config = (repo_root / "opencode.jsonc").read_text(encoding="utf-8") - assert '"openai/o3"' in opencode_config - assert '"openai/o4-mini"' in opencode_config assert_local_review_workflows_removed() assert "selected workflow mutation" in policy assert "credential, not by a maintainer's local `gh` session" in policy From 17fbd43f7741a2565de283456957dcf3d07e1a18 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 01:18:41 +0900 Subject: [PATCH 2/7] test(automation): require canonical NVIDIA NIM secret --- .../tests/test_opencode_nim_secret_contract.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 services/analysis-engine/tests/test_opencode_nim_secret_contract.py diff --git a/services/analysis-engine/tests/test_opencode_nim_secret_contract.py b/services/analysis-engine/tests/test_opencode_nim_secret_contract.py new file mode 100644 index 000000000..139d87ea1 --- /dev/null +++ b/services/analysis-engine/tests/test_opencode_nim_secret_contract.py @@ -0,0 +1,15 @@ +"""Regression contract for the repository's NVIDIA NIM OpenCode credential binding.""" + +from __future__ import annotations + +import json +from pathlib import Path + + +def test_opencode_uses_the_canonical_nvidia_nim_secret_name() -> None: + """Bind local OpenCode to the organization-standard NVIDIA NIM secret name.""" + repo_root = Path(__file__).resolve().parents[3] + config = json.loads((repo_root / "opencode.jsonc").read_text(encoding="utf-8")) + + provider = config["provider"]["nvidia-nim"] + assert provider["options"]["apiKey"] == "{env:NVIDIA_NIM_API_KEY}" From d3d9fc053efb66f5214c7ee638e67ec473555a80 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 01:19:30 +0900 Subject: [PATCH 3/7] fix(automation): bind OpenCode to NVIDIA_NIM_API_KEY --- opencode.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opencode.jsonc b/opencode.jsonc index eeca34f1b..b0199a1d2 100644 --- a/opencode.jsonc +++ b/opencode.jsonc @@ -42,7 +42,7 @@ "name": "NVIDIA NIM", "options": { "baseURL": "https://integrate.api.nvidia.com/v1", - "apiKey": "{env:NVIDIA_API_KEY}" + "apiKey": "{env:NVIDIA_NIM_API_KEY}" }, "models": { "nvidia/llama-3.3-nemotron-super-49b-v1.5": { From 1be34db6bcf6e248a45ba073688cab519adec98a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 01:22:12 +0900 Subject: [PATCH 4/7] test(automation): lock NIM model and credential contract --- .../test_opencode_nim_secret_contract.py | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/services/analysis-engine/tests/test_opencode_nim_secret_contract.py b/services/analysis-engine/tests/test_opencode_nim_secret_contract.py index 139d87ea1..2b4e2391a 100644 --- a/services/analysis-engine/tests/test_opencode_nim_secret_contract.py +++ b/services/analysis-engine/tests/test_opencode_nim_secret_contract.py @@ -1,4 +1,4 @@ -"""Regression contract for the repository's NVIDIA NIM OpenCode credential binding.""" +"""Regression contract for the repository's NVIDIA NIM OpenCode configuration.""" from __future__ import annotations @@ -6,10 +6,36 @@ from pathlib import Path -def test_opencode_uses_the_canonical_nvidia_nim_secret_name() -> None: - """Bind local OpenCode to the organization-standard NVIDIA NIM secret name.""" +def test_opencode_uses_the_canonical_nvidia_nim_contract() -> None: + """Require the reviewed NIM models, process credential alias, and option boundary.""" repo_root = Path(__file__).resolve().parents[3] - config = json.loads((repo_root / "opencode.jsonc").read_text(encoding="utf-8")) + opencode_text = (repo_root / "opencode.jsonc").read_text(encoding="utf-8") + config = json.loads(opencode_text) + + assert config["model"] == "nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5" + assert config["small_model"] == "nvidia-nim/meta/llama-3.3-70b-instruct" + assert config["enabled_providers"] == ["nvidia-nim"] + assert set(config["provider"]) == {"nvidia-nim"} provider = config["provider"]["nvidia-nim"] - assert provider["options"]["apiKey"] == "{env:NVIDIA_NIM_API_KEY}" + assert provider["options"]["baseURL"] == "https://integrate.api.nvidia.com/v1" + # Central workflows source GitHub Secret NVIDIA_NIM_API_KEY and intentionally + # expose it to this OpenCode-compatible client through the NVIDIA_API_KEY + # process alias. The repository config must consume the alias, not rename + # the organization secret contract. + assert provider["options"]["apiKey"] == "{env:NVIDIA_API_KEY}" + + primary_model = provider["models"]["nvidia/llama-3.3-nemotron-super-49b-v1.5"] + assert "reasoningEffort" not in primary_model.get("options", {}) + assert "meta/llama-3.3-70b-instruct" in provider["models"] + + for forbidden_token in ( + "github-models", + "STRIX_GITHUB_MODELS_TOKEN", + "COPILOT_GITHUB_TOKEN", + "openai/gpt-5", + "openai/o3", + "openai/o4-mini", + "models.github.ai", + ): + assert forbidden_token not in opencode_text From d583202e9e4db43c69c8b0cb873fbf3a1d5332f8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 01:22:32 +0900 Subject: [PATCH 5/7] fix(automation): use supported NIM reasoning and env alias --- opencode.jsonc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/opencode.jsonc b/opencode.jsonc index b0199a1d2..d4d22d611 100644 --- a/opencode.jsonc +++ b/opencode.jsonc @@ -42,16 +42,13 @@ "name": "NVIDIA NIM", "options": { "baseURL": "https://integrate.api.nvidia.com/v1", - "apiKey": "{env:NVIDIA_NIM_API_KEY}" + "apiKey": "{env:NVIDIA_API_KEY}" }, "models": { "nvidia/llama-3.3-nemotron-super-49b-v1.5": { "name": "NVIDIA Llama 3.3 Nemotron Super 49B v1.5", "tool_call": true, "reasoning": true, - "options": { - "reasoningEffort": "high" - }, "limit": { "context": 131072, "output": 32768 From 367bd5d6b119189937a1057ac6f8578e7b0f6f3f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 01:26:43 +0900 Subject: [PATCH 6/7] docs(agents): record local NIM credential boundary --- AGENTS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index fca448ce9..5c98b43a5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -98,3 +98,10 @@ This section applies to any agent (Claude, Codex, Cursor, opencode, ...) working - Do not justify risky debug defaults as temporary shortcuts. - Do not defer dependency review, SBOM generation, or supply-chain checks to a later phase. - Do not defer Windows or macOS build enforcement to a later phase. + +## Local OpenCode contract +- Root `opencode.jsonc` is NVIDIA NIM only: `enabled_providers` is `["nvidia-nim"]`. +- The provider binds `{env:NVIDIA_API_KEY}` to `https://integrate.api.nvidia.com/v1`. That env name is the NVIDIA/OpenCode client contract. +- The organization GitHub secret is `NVIDIA_NIM_API_KEY`. CI maps that secret onto process env `NVIDIA_API_KEY`. Do not rename the local OpenCode binding to `{env:NVIDIA_NIM_API_KEY}`. +- Never introduce `COPILOT_GITHUB_TOKEN`, `github-models`, or `STRIX_GITHUB_MODELS_TOKEN` in `opencode.jsonc`. +- Do not change existing review-agent credential names or routing. Central OpenCode Review and the PR review/merge scheduler stay in `ContextualWisdomLab/.github`. From 6ca06d3f3a8c65ced1c0f760e66094b8a11b0168 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 01:27:05 +0900 Subject: [PATCH 7/7] docs(workflow): separate local NIM from central review credentials --- docs/workflow/pr-review-merge-scheduler.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/workflow/pr-review-merge-scheduler.md b/docs/workflow/pr-review-merge-scheduler.md index adcb9baeb..c13e59d75 100644 --- a/docs/workflow/pr-review-merge-scheduler.md +++ b/docs/workflow/pr-review-merge-scheduler.md @@ -16,6 +16,12 @@ workflow `GITHUB_TOKEN`, depending on which credential can perform the guarded r The local repository may keep product CI, security, release, and build workflows. It must not restore repo-local copies of `opencode-review.yml`, `pr-review-merge-scheduler.yml`, or their `scripts/ci` helper implementations. +Local developer OpenCode (`opencode.jsonc`) is a separate trust boundary from those central +review workflows. It uses NVIDIA NIM only, binds `{env:NVIDIA_API_KEY}` at +`https://integrate.api.nvidia.com/v1`, and must not restore GitHub Models, Copilot tokens, or +review-agent secrets. The organization secret name remains `NVIDIA_NIM_API_KEY`; CI maps that +secret onto `NVIDIA_API_KEY` for the OpenCode client. + ## Behavior - Inspect non-draft PRs targeting the repository default branch, currently `develop`. @@ -44,8 +50,8 @@ repo-local copies of `opencode-review.yml`, `pr-review-merge-scheduler.yml`, or ## Security Notes -- Attack surface: organization required workflows with write access to PR comments, PR branch updates, and normal merges. -- Trust boundary touched: GitHub repository governance, PR review state, status checks, and CodeRabbit review requests. +- Attack surface: organization required workflows with write access to PR comments, PR branch updates, and normal merges; local `opencode.jsonc` that calls NVIDIA NIM over HTTPS. +- Trust boundary touched: GitHub repository governance, PR review state, status checks, CodeRabbit review requests, and the local OpenCode provider allowlist (`nvidia-nim` + `{env:NVIDIA_API_KEY}`). - Realistic threats: spammed review comments, merging a PR with unresolved conversations, merging without required checks, or hiding conflicts behind automation. - Mitigations: central required workflow source pinning, idempotent per-head review comment marker, explicit unresolved-thread check, retry-bounded GitHub API reads, required-check verification @@ -54,4 +60,5 @@ repo-local copies of `opencode-review.yml`, `pr-review-merge-scheduler.yml`, or - Test points: organization ruleset inheritance, current-head OpenCode approval, unresolved review thread count, required-check rollup, approved behind PR, approved conflict-free PR, approved dirty PR, external failed-check classification, provider/runtime failure summary, and Strix evidence lookup - scope diagnostics. + scope diagnostics, and local `opencode.jsonc` NIM-only contract (`small_model`, `{env:NVIDIA_API_KEY}`, + no GitHub Models / Copilot leftovers).