Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 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
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
15 changes: 11 additions & 4 deletions docs/workflow/pr-review-merge-scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -44,14 +50,15 @@ 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
through GitHub, conflict skip, guarded merge with `--match-head-commit`, and no admin bypass path.
- Remaining risk: CodeRabbit and GitHub check state can be delayed or stale; the scheduler therefore only advances eligible PRs and leaves code-fix work to agents or maintainers.
- 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.
external failed-check classification, provider/runtime failure summary, Strix evidence lookup
scope diagnostics, and local `opencode.jsonc` NIM-only contract (`small_model`, `{env:NVIDIA_API_KEY}`,
no GitHub Models / Copilot leftovers).
60 changes: 18 additions & 42 deletions opencode.jsonc
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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"
Comment thread
cursor[bot] marked this conversation as resolved.
Resolved
},
"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
}
}
}
Expand Down
34 changes: 30 additions & 4 deletions services/analysis-engine/tests/test_supply_chain_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -5073,14 +5073,40 @@ 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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: json.loads on .jsonc breaks if comments are added

test_opencode_uses_nvidia_nim_only parses opencode.jsonc with json.loads (services/analysis-engine/tests/test_supply_chain_policy.py:5080). The .jsonc format allows comments and trailing commas; the file currently has none. Adding either later would fail parsing with a decode error rather than a clear contract assertion.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


assert opencode_config["model"] == "nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5"
assert opencode_config["small_model"] == "nvidia-nim/meta/llama-3.3-70b-instruct"
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"]
assert "meta/llama-3.3-70b-instruct" in nim_provider["models"]

leftover_tokens = (
"github-models",
"STRIX_GITHUB_MODELS_TOKEN",
"COPILOT_GITHUB_TOKEN",
"openai/gpt-5",
"openai/o3",
"openai/o4-mini",
"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
Expand Down
Loading