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
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,11 @@ 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 set OpenAI-style `reasoningEffort` on `nvidia/llama-3.3-nemotron-super-49b-v1.5`. NIM uses `chat_template_kwargs` for that model (see `docs/doctoring/opencode-nvidia-nim-contract.md`).
- Do not change existing review-agent credential names or routing. Central OpenCode Review and the PR review/merge scheduler stay in `ContextualWisdomLab/.github`.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,4 @@ Supporting packages:
- Lockfiles (`package-lock.json`, `uv.lock`, `Cargo.lock`) are committed and must stay in sync; GitHub Actions are SHA-pinned. Adding a direct dependency requires the admission rationale defined in `AGENTS.md` and `docs/security/dependency-policy.md`.
- CI beyond quickcheck: `gate / ci / rust-check` (Tauri cargo check on macOS) and `build-baseline` Windows/macOS amd64+arm64 native builds are merge gates, alongside CodeQL, dependency-review, sbom, bandit, trivy, secret-scan, and security-audit workflows. Do not weaken or skip them.
- Version metadata lives in `VERSION`, the root `package.json`, and `CHANGELOG.md`; release flow is tag-driven (see `docs/operations/deploy-runbook.md`).
- Local developer OpenCode is NVIDIA NIM only. The binding, secret split, leftover-token deny-list, and `reasoningEffort` ban live in `AGENTS.md` (`Local OpenCode contract`) and `docs/doctoring/opencode-nvidia-nim-contract.md`.
53 changes: 53 additions & 0 deletions docs/doctoring/opencode-nvidia-nim-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Local OpenCode NVIDIA NIM contract

Next action: keep root `opencode.jsonc` on NVIDIA NIM only. Bind `{env:NVIDIA_API_KEY}` to
`https://integrate.api.nvidia.com/v1`. Do not rename that local binding to the organization
secret name `NVIDIA_NIM_API_KEY`. Do not put OpenAI-style `reasoningEffort` anywhere in the
local OpenCode configuration.

## Why this lock exists

Local developer OpenCode is a separate trust boundary from central OpenCode Review and the
PR review/merge scheduler in `ContextualWisdomLab/.github`. Those workflows keep their own
credential names. This repository only records the local client allowlist.

NVIDIA NIM reasoning models use `chat_template_kwargs` (for example `enable_thinking`) rather
than the OpenAI `reasoning_effort` field. NVIDIA documents `reasoning_effort` as a Chat
Completions knob for GPT-OSS models on multi-LLM NIM, not for Llama 3.3 Nemotron Super 49B
v1.5 (NVIDIA, n.d.-a; NVIDIA, n.d.-b). Forwarding `reasoningEffort` from OpenCode can be
ignored or rejected. The contract therefore forbids that OpenCode option across the whole
repository config instead of checking only one model's nested `options` object.

The organization GitHub secret remains `NVIDIA_NIM_API_KEY`. CI maps that secret onto process
env `NVIDIA_API_KEY` because that is the NVIDIA/OpenCode client binding.

## Held values

- `enabled_providers`: `["nvidia-nim"]`
- default model: `nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5`
- `small_model`: `nvidia-nim/meta/llama-3.3-70b-instruct`
- `apiKey`: `{env:NVIDIA_API_KEY}`
- leftover deny-list: `github-models`, `STRIX_GITHUB_MODELS_TOKEN`, `COPILOT_GITHUB_TOKEN`,
`openai/gpt-5`, `openai/o3`, `openai/o4-mini`, `models.github.ai`

## References

NVIDIA. (n.d.-a). *Use reasoning models with NVIDIA NIM for LLMs*.
https://docs.nvidia.com/nim/large-language-models/latest/reasoning-model.html

NVIDIA. (n.d.-b). *nvidia / llama-3.3-nemotron-super-49b-v1.5*.
https://docs.api.nvidia.com/nim/reference/nvidia-llama-3_3-nemotron-super-49b-v1_5

## Security Notes

- Attack surface: local OpenCode HTTPS calls to `https://integrate.api.nvidia.com/v1` using a
process-env API key.
- Trust boundary: untrusted prompts and repository contents sent to the provider; trusted
repo-controlled provider allowlist; secret name `NVIDIA_NIM_API_KEY` stays in GitHub and is
mapped onto `NVIDIA_API_KEY` only at process start.
- Mitigations: single enabled provider, no GitHub Models or Copilot token fallback, leftover
string deny-list, and explicit whole-config bans on `reasoningEffort` and
`{env:NVIDIA_NIM_API_KEY}` inside `opencode.jsonc`.
- Test points: `test_opencode_uses_nvidia_nim_only` owns the structured provider/model/secret
contract; `test_opencode_forbids_reasoning_effort_anywhere` independently prevents the
forbidden OpenAI-style option from being pasted at any config level.
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 developer OpenCode (`opencode.jsonc`) is a separate HTTPS client to NVIDIA NIM and is not invoked by this scheduler.
- Trust boundary touched: GitHub repository governance, PR review state, status checks, and CodeRabbit review requests. The local OpenCode provider allowlist (`nvidia-nim` + `{env:NVIDIA_API_KEY}`) is recorded here so agents do not restore GitHub Models or review-agent secrets into this repository.
- 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 the separate local `opencode.jsonc` NIM-only contract (`small_model`,
`{env:NVIDIA_API_KEY}`, no `reasoningEffort`, no GitHub Models / Copilot leftovers).
57 changes: 15 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,29 @@
}
},
"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,
"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
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Focused regression for forbidden OpenCode reasoning options."""

from __future__ import annotations

from pathlib import Path


def test_opencode_forbids_reasoning_effort_anywhere() -> None:
"""Reject OpenAI-style reasoningEffort anywhere in the local NIM config."""
repo_root = Path(__file__).resolve().parents[3]
opencode_text = (repo_root / "opencode.jsonc").read_text(encoding="utf-8")

assert '"reasoningEffort"' not in opencode_text
38 changes: 34 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,44 @@ 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"]

primary_model = nim_provider["models"]["nvidia/llama-3.3-nemotron-super-49b-v1.5"]
assert "reasoningEffort" not in primary_model.get("options", {})
assert "{env:NVIDIA_NIM_API_KEY}" not in opencode_text
Comment on lines +5076 to +5095

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: opencode.jsonc parses as strict JSON

test_opencode_uses_nvidia_nim_only calls json.loads on opencode.jsonc. Despite the .jsonc extension the file has no comments or trailing commas, so strict parsing succeeds. json is imported and parents[3] resolves to the repo root.

Open in Devin Review

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


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