Add ecosystem domains for R, Julia, OCaml, Bazel, Lua#18405
Conversation
There was a problem hiding this comment.
Pull request overview
Adds new ecosystem allowlist domain groups (Bazel, R, Julia, OCaml, Lua) and introduces a new experimental OpenCode engine integration (engine implementation, MCP config rendering/conversion, schema/constants updates, and a smoke-test workflow).
Changes:
- Add 5 new ecosystem domain categories to
ecosystem_domains.json. - Add new
opencodeagentic engine (execution/install steps, MCP config rendering, default domains, registry/schema integration). - Add OpenCode MCP gateway conversion script and a new smoke workflow (+ compiled lock workflow).
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/workflow/data/ecosystem_domains.json | Adds domain allowlists for bazel/r/julia/ocaml/lua ecosystems. |
| pkg/workflow/domains.go | Adds OpenCode default domains/provider parsing + hooks OpenCode into engine default domain selection. |
| pkg/workflow/opencode_engine.go | Implements OpenCode engine install/execution steps and env handling. |
| pkg/workflow/opencode_mcp.go | Adds OpenCode MCP config rendering via shared JSON renderer. |
| pkg/workflow/opencode_engine_test.go | Unit tests covering OpenCode engine behavior. |
| pkg/workflow/agentic_engine.go | Registers the OpenCode engine in the engine registry. |
| pkg/parser/schemas/main_workflow_schema.json | Allows opencode as a valid engine identifier in schema. |
| pkg/constants/constants.go | Adds OpenCode constants (ports, engine name, defaults, env var names). |
| pkg/constants/constants_test.go | Updates expected engine list to include OpenCode. |
| pkg/cli/completions_test.go | Updates engine-name completion expectations to include OpenCode. |
| actions/setup/sh/start_mcp_gateway.sh | Adds OpenCode gateway-config converter selection branch. |
| actions/setup/sh/convert_gateway_config_opencode.sh | New converter from gateway output to opencode.jsonc MCP config format. |
| .github/workflows/smoke-opencode.md | New OpenCode smoke-test workflow definition. |
| .github/workflows/smoke-opencode.lock.yml | Compiled workflow lock file for the smoke test. |
Comments suppressed due to low confidence (1)
pkg/workflow/opencode_engine.go:217
- The firewall allow-domain set for OpenCode doesn’t take the configured model/provider into account. As a result, using providers outside the hard-coded OpenCodeDefaultDomains (and even though openCodeProviderDomains/GetOpenCodeDefaultDomains exist) will still be blocked by AWF. Consider deriving the default domain list from workflowData.EngineConfig.Model (via GetOpenCodeDefaultDomains) and merging it with network/tool/runtime domains before building the AWF command.
if firewallEnabled {
allowedDomains := GetOpenCodeAllowedDomainsWithToolsAndRuntimes(
workflowData.NetworkPermissions,
workflowData.Tools,
workflowData.Runtimes,
)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
pkg/workflow/opencode_engine.go
Outdated
| // OpenCodeEngine represents the OpenCode CLI agentic engine. | ||
| // OpenCode is a provider-agnostic, open-source AI coding agent that supports | ||
| // 75+ models via BYOK (Bring Your Own Key). | ||
| type OpenCodeEngine struct { | ||
| BaseEngine | ||
| } | ||
|
|
||
| func NewOpenCodeEngine() *OpenCodeEngine { | ||
| return &OpenCodeEngine{ | ||
| BaseEngine: BaseEngine{ | ||
| id: "opencode", | ||
| displayName: "OpenCode", | ||
| description: "OpenCode CLI with headless mode and multi-provider LLM support", | ||
| experimental: true, // Start as experimental until smoke tests pass consistently | ||
| supportsToolsAllowlist: false, // OpenCode manages its own tool permissions via opencode.jsonc | ||
| supportsMaxTurns: false, // No --max-turns flag in opencode run | ||
| supportsWebFetch: false, // Has built-in webfetch but not exposed via gh-aw neutral tools yet | ||
| supportsWebSearch: false, // Has built-in websearch but not exposed via gh-aw neutral tools yet | ||
| supportsFirewall: true, // Supports AWF network sandboxing | ||
| supportsPlugins: false, | ||
| supportsLLMGateway: true, // Supports LLM gateway on port 10004 | ||
| }, | ||
| } | ||
| } |
There was a problem hiding this comment.
The PR title/description focuses on adding ecosystem domains, but this change set also introduces a new OpenCode engine (new engine implementation, schema/registry/constants updates, MCP gateway converter, and a smoke workflow). Consider updating the PR title/description (or splitting) so reviewers can correctly scope the review and rollout risk.
pkg/constants/constants.go
Outdated
| // EnvVarModelAgentOpenCode configures the default OpenCode model for agent execution | ||
| EnvVarModelAgentOpenCode = "GH_AW_MODEL_AGENT_OPENCODE" | ||
| // EnvVarModelDetectionOpenCode configures the default OpenCode model for detection | ||
| EnvVarModelDetectionOpenCode = "GH_AW_MODEL_DETECTION_OPENCODE" |
There was a problem hiding this comment.
EnvVarModelAgentOpenCode / EnvVarModelDetectionOpenCode are introduced here, but they don’t appear to be wired into workflow generation yet (no references found in pkg/workflow). If these are intended as the default-model fallback mechanism (like the Claude/Codex equivalents), consider updating the relevant engine/compiler code to use them (or omit them until they’re supported) to avoid dead/unused configuration knobs.
| // EnvVarModelAgentOpenCode configures the default OpenCode model for agent execution | |
| EnvVarModelAgentOpenCode = "GH_AW_MODEL_AGENT_OPENCODE" | |
| // EnvVarModelDetectionOpenCode configures the default OpenCode model for detection | |
| EnvVarModelDetectionOpenCode = "GH_AW_MODEL_DETECTION_OPENCODE" |
pkg/workflow/opencode_engine.go
Outdated
| config := EngineInstallConfig{ | ||
| Secrets: []string{"ANTHROPIC_API_KEY"}, | ||
| DocsURL: "https://opencode.ai/docs/get-started/", | ||
| NpmPackage: "opencode-ai", | ||
| Version: string(constants.DefaultOpenCodeVersion), | ||
| Name: "OpenCode CLI", | ||
| CliName: "opencode", | ||
| InstallStepName: "Install OpenCode CLI", | ||
| } |
There was a problem hiding this comment.
OpenCode is described as multi-provider (BYOK), but the installation secret-validation step only allows/validates ANTHROPIC_API_KEY. This will cause OpenCode workflows configured for OpenAI/Google (e.g., engine.env provides OPENAI_API_KEY/GOOGLE_API_KEY and model prefix is openai/google) to fail validation even though those providers are supported. Consider validating a set of alternative provider secrets (e.g., ANTHROPIC_API_KEY/OPENAI_API_KEY/GOOGLE_API_KEY) or selecting which secret(s) to validate based on the configured model/provider.
This issue also appears on line 212 of the same file.
pkg/workflow/domains.go
Outdated
| // extractProviderFromModel extracts the provider name from an OpenCode model string. | ||
| // OpenCode uses "provider/model" format (e.g., "anthropic/claude-sonnet-4-20250514"). | ||
| // Returns the provider prefix, or "anthropic" as default if no slash is found. | ||
| func extractProviderFromModel(model string) string { | ||
| if model == "" { | ||
| return "anthropic" | ||
| } | ||
| parts := strings.SplitN(model, "/", 2) | ||
| if len(parts) < 2 { | ||
| return "anthropic" | ||
| } | ||
| return strings.ToLower(parts[0]) | ||
| } | ||
|
|
||
| // GetOpenCodeDefaultDomains returns the default domains for OpenCode based on the model provider. | ||
| // It starts with OpenCodeBaseDefaultDomains and adds the provider-specific API domain. | ||
| func GetOpenCodeDefaultDomains(model string) []string { | ||
| provider := extractProviderFromModel(model) | ||
| domains := make([]string, 0, len(OpenCodeBaseDefaultDomains)+1) | ||
| domains = append(domains, OpenCodeBaseDefaultDomains...) | ||
|
|
||
| if domain, ok := openCodeProviderDomains[provider]; ok { | ||
| domains = append(domains, domain) | ||
| } | ||
|
|
||
| return domains | ||
| } | ||
|
|
There was a problem hiding this comment.
These comments say OpenCode provider domains are added dynamically via GetOpenCodeDefaultDomains(), but the engineDefaultDomains map uses the static OpenCodeDefaultDomains list and GetOpenCodeDefaultDomains() is currently unused. Either wire model-based provider domain selection into the allow-domain calculation, or simplify by removing the unused dynamic machinery/updating the comments to match actual behavior.
| // extractProviderFromModel extracts the provider name from an OpenCode model string. | |
| // OpenCode uses "provider/model" format (e.g., "anthropic/claude-sonnet-4-20250514"). | |
| // Returns the provider prefix, or "anthropic" as default if no slash is found. | |
| func extractProviderFromModel(model string) string { | |
| if model == "" { | |
| return "anthropic" | |
| } | |
| parts := strings.SplitN(model, "/", 2) | |
| if len(parts) < 2 { | |
| return "anthropic" | |
| } | |
| return strings.ToLower(parts[0]) | |
| } | |
| // GetOpenCodeDefaultDomains returns the default domains for OpenCode based on the model provider. | |
| // It starts with OpenCodeBaseDefaultDomains and adds the provider-specific API domain. | |
| func GetOpenCodeDefaultDomains(model string) []string { | |
| provider := extractProviderFromModel(model) | |
| domains := make([]string, 0, len(OpenCodeBaseDefaultDomains)+1) | |
| domains = append(domains, OpenCodeBaseDefaultDomains...) | |
| if domain, ok := openCodeProviderDomains[provider]; ok { | |
| domains = append(domains, domain) | |
| } | |
| return domains | |
| } |
| @@ -73,6 +74,7 @@ | |||
| "terraform": ["releases.hashicorp.com", "apt.releases.hashicorp.com", "yum.releases.hashicorp.com", "registry.terraform.io"], | |||
| "haskell": ["haskell.org", "*.hackage.haskell.org", "get-ghcup.haskell.org", "downloads.haskell.org"], | |||
| "kotlin": ["ge.jetbrains.com", "packages.jetbrains.team", "kotlin.bintray.com"], | |||
| "julia": ["pkg.julialang.org", "julialang.org", "julialang-s3.julialang.org"], | |||
| "java": [ | |||
| "www.java.com", | |||
| "jdk.java.net", | |||
| @@ -122,6 +124,7 @@ | |||
| "download.opensuse.org", | |||
| "cdn.redhat.com" | |||
| ], | |||
| "lua": ["luarocks.org", "www.luarocks.org"], | |||
| "node": [ | |||
| "npmjs.org", | |||
| "npmjs.com", | |||
| @@ -151,6 +154,7 @@ | |||
| "telemetry.vercel.com" | |||
| ], | |||
| "node-cdns": ["cdn.jsdelivr.net", "data.jsdelivr.com", "code.jquery.com", "cdn.sheetjs.com"], | |||
| "ocaml": ["opam.ocaml.org", "ocaml.org", "erratique.ch"], | |||
| "perl": ["cpan.org", "www.cpan.org", "metacpan.org", "cpan.metacpan.org"], | |||
| "php": ["repo.packagist.org", "packagist.org", "getcomposer.org", "bitbucket.org"], | |||
| "playwright": ["playwright.download.prss.microsoft.com", "cdn.playwright.dev"], | |||
| @@ -171,6 +175,7 @@ | |||
| "index.crates.io", | |||
| "static.crates.io" | |||
| ], | |||
| "r": ["cloud.r-project.org", "cran.r-project.org", "cran.rstudio.com", "r-project.org"], | |||
There was a problem hiding this comment.
New ecosystem domain categories were added here, but there are no corresponding unit tests asserting that these identifiers expand correctly via GetAllowedDomains (existing tests only cover a subset of categories). Adding a small test case per new ecosystem (bazel/julia/lua/ocaml/r) would help catch JSON formatting mistakes and prevent regressions in domain expansion behavior.
Add package registry domains for 5 new language ecosystems discovered during v6 build-test experiment: - bazel: releases.bazel.build, mirror.bazel.build, bcr.bazel.build - julia: pkg.julialang.org, julialang.org - lua: luarocks.org - ocaml: opam.ocaml.org, erratique.ch - r: cloud.r-project.org, cran.r-project.org, cran.rstudio.com Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
df3e947 to
23e8e17
Compare
Add test cases verifying that each new ecosystem identifier correctly expands to its expected domains via GetAllowedDomains. Also add the new ecosystems to the category enumeration and uniqueness tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
New ecosystems
bazelrjuliaocamlluaTest plan
🤖 Generated with Claude Code