diff --git a/pkg/workflow/agentic_engine.go b/pkg/workflow/agentic_engine.go index d0fd1ceaf2..565429c398 100644 --- a/pkg/workflow/agentic_engine.go +++ b/pkg/workflow/agentic_engine.go @@ -124,13 +124,6 @@ type CapabilityProvider interface { // SupportsMaxContinuations returns true if this engine supports the max-continuations feature // When true, max-continuations > 1 enables autopilot/multi-run mode for the engine SupportsMaxContinuations() bool - - // SupportsLLMGateway returns the LLM gateway port number for this engine - // Returns the port number (e.g., 10000) if the engine supports an LLM gateway - // Returns -1 if the engine does not support an LLM gateway - // The port is used to configure AWF api-proxy sidecar container - // In strict mode, engines without LLM gateway support require additional security constraints - SupportsLLMGateway() int } // WorkflowExecutor handles workflow compilation and execution @@ -226,7 +219,6 @@ type BaseEngine struct { supportsWebFetch bool supportsWebSearch bool supportsPlugins bool - supportsLLMGateway bool } func (e *BaseEngine) GetID() string { @@ -269,12 +261,6 @@ func (e *BaseEngine) SupportsMaxContinuations() bool { return e.supportsMaxContinuations } -func (e *BaseEngine) SupportsLLMGateway() int { - // Engines that support LLM gateway must override this method - // to return their specific port number (e.g., 10000, 10001, 10002) - return -1 -} - // GetDeclaredOutputFiles returns an empty list by default (engines can override) func (e *BaseEngine) GetDeclaredOutputFiles() []string { return []string{} diff --git a/pkg/workflow/claude_engine.go b/pkg/workflow/claude_engine.go index 4197be967d..570070604b 100644 --- a/pkg/workflow/claude_engine.go +++ b/pkg/workflow/claude_engine.go @@ -26,19 +26,13 @@ func NewClaudeEngine() *ClaudeEngine { description: "Uses Claude Code with full MCP tool support and allow-listing", experimental: false, supportsToolsAllowlist: true, - supportsMaxTurns: true, // Claude supports max-turns feature - supportsWebFetch: true, // Claude has built-in WebFetch support - supportsWebSearch: true, // Claude has built-in WebSearch support - supportsLLMGateway: false, // Claude does not support LLM gateway + supportsMaxTurns: true, // Claude supports max-turns feature + supportsWebFetch: true, // Claude has built-in WebFetch support + supportsWebSearch: true, // Claude has built-in WebSearch support }, } } -// SupportsLLMGateway returns the LLM gateway port for Claude engine -func (e *ClaudeEngine) SupportsLLMGateway() int { - return constants.ClaudeLLMGatewayPort -} - // GetModelEnvVarName returns the native environment variable name that the Claude Code CLI uses // for model selection. Setting ANTHROPIC_MODEL is equivalent to passing --model to the CLI. func (e *ClaudeEngine) GetModelEnvVarName() string { @@ -281,8 +275,7 @@ func (e *ClaudeEngine) GetExecutionSteps(workflowData *WorkflowData, logFile str allowedDomains := GetClaudeAllowedDomainsWithToolsAndRuntimes(workflowData.NetworkPermissions, workflowData.Tools, workflowData.Runtimes) // Enable API proxy sidecar if this engine supports LLM gateway - llmGatewayPort := e.SupportsLLMGateway() - usesAPIProxy := llmGatewayPort > 0 + usesAPIProxy := true // Build AWF command with all configuration // AWF v0.15.0+ uses chroot mode by default, providing transparent access to host binaries diff --git a/pkg/workflow/codex_engine.go b/pkg/workflow/codex_engine.go index d8265dfe76..d44dd102e2 100644 --- a/pkg/workflow/codex_engine.go +++ b/pkg/workflow/codex_engine.go @@ -41,16 +41,10 @@ func NewCodexEngine() *CodexEngine { supportsMaxTurns: false, // Codex does not support max-turns feature supportsWebFetch: false, // Codex does not have built-in web-fetch support supportsWebSearch: true, // Codex has built-in web-search support - supportsLLMGateway: true, // Codex supports LLM gateway on port 10001 }, } } -// SupportsLLMGateway returns the LLM gateway port for Codex engine -func (e *CodexEngine) SupportsLLMGateway() int { - return constants.CodexLLMGatewayPort -} - // GetModelEnvVarName returns an empty string because the Codex CLI does not support // selecting the model via a native environment variable. Model selection for Codex // is done via the -c model=... configuration override in the shell command. @@ -206,9 +200,7 @@ func (e *CodexEngine) GetExecutionSteps(workflowData *WorkflowData, logFile stri // Get allowed domains (Codex defaults + network permissions + HTTP MCP server URLs + runtime ecosystem domains) allowedDomains := GetCodexAllowedDomainsWithToolsAndRuntimes(workflowData.NetworkPermissions, workflowData.Tools, workflowData.Runtimes) - // Enable API proxy sidecar if this engine supports LLM gateway - llmGatewayPort := e.SupportsLLMGateway() - usesAPIProxy := llmGatewayPort > 0 + usesAPIProxy := true // Build the command with agent file handling if specified // INSTRUCTION reading is done inside the AWF command to avoid Docker Compose interpolation diff --git a/pkg/workflow/copilot_engine.go b/pkg/workflow/copilot_engine.go index 462e6e7380..dc082dc672 100644 --- a/pkg/workflow/copilot_engine.go +++ b/pkg/workflow/copilot_engine.go @@ -44,7 +44,6 @@ func NewCopilotEngine() *CopilotEngine { supportsWebFetch: true, // Copilot CLI has built-in web-fetch support supportsWebSearch: false, // Copilot CLI does not have built-in web-search support supportsPlugins: true, // Copilot supports plugin installation - supportsLLMGateway: true, // Copilot supports LLM gateway on port 10003 }, } } @@ -61,11 +60,6 @@ func (e *CopilotEngine) GetModelEnvVarName() string { return constants.CopilotCLIModelEnvVar } -// SupportsLLMGateway returns the LLM gateway port for Copilot engine -func (e *CopilotEngine) SupportsLLMGateway() int { - return constants.CopilotLLMGatewayPort -} - // GetRequiredSecretNames returns the list of secrets required by the Copilot engine // This includes COPILOT_GITHUB_TOKEN and optionally MCP_GATEWAY_API_KEY func (e *CopilotEngine) GetRequiredSecretNames(workflowData *WorkflowData) []string { diff --git a/pkg/workflow/copilot_engine_execution.go b/pkg/workflow/copilot_engine_execution.go index a7b7ea8d16..ecc6ec7968 100644 --- a/pkg/workflow/copilot_engine_execution.go +++ b/pkg/workflow/copilot_engine_execution.go @@ -203,9 +203,7 @@ func (e *CopilotEngine) GetExecutionSteps(workflowData *WorkflowData, logFile st allowedDomains := GetCopilotAllowedDomainsWithToolsAndRuntimes(workflowData.NetworkPermissions, workflowData.Tools, workflowData.Runtimes) // Build AWF command with all configuration - // Enable API proxy sidecar if this engine supports LLM gateway - llmGatewayPort := e.SupportsLLMGateway() - usesAPIProxy := llmGatewayPort > 0 + usesAPIProxy := true // AWF v0.15.0+ uses chroot mode by default, providing transparent access to host binaries // AWF v0.15.0+ with --env-all handles PATH natively (chroot mode is default): diff --git a/pkg/workflow/docker.go b/pkg/workflow/docker.go index e206a72fcf..3f29bd96ee 100644 --- a/pkg/workflow/docker.go +++ b/pkg/workflow/docker.go @@ -105,19 +105,16 @@ func collectDockerImages(tools map[string]any, workflowData *WorkflowData, actio dockerLog.Printf("Added AWF agent container: %s", agentImage) } - // Add api-proxy sidecar container for engines that support LLM gateway + // Add api-proxy sidecar container for LLM gateway support // The api-proxy holds LLM API keys securely and proxies requests through Squid - // Each engine uses its own dedicated port for communication - // Check if the engine supports LLM gateway by querying the engine registry if workflowData != nil && workflowData.AI != "" { registry := GetGlobalEngineRegistry() - engine, err := registry.GetEngine(workflowData.AI) - if err == nil && engine.SupportsLLMGateway() > 0 { + if _, err := registry.GetEngine(workflowData.AI); err == nil { apiProxyImage := constants.DefaultFirewallRegistry + "/api-proxy:" + awfImageTag if !imageSet[apiProxyImage] { images = append(images, apiProxyImage) imageSet[apiProxyImage] = true - dockerLog.Printf("Added AWF api-proxy sidecar container for engine with LLM gateway support: %s", apiProxyImage) + dockerLog.Printf("Added AWF api-proxy sidecar container: %s", apiProxyImage) } } } diff --git a/pkg/workflow/gemini_engine.go b/pkg/workflow/gemini_engine.go index 563a6c679d..c70d9bbd3c 100644 --- a/pkg/workflow/gemini_engine.go +++ b/pkg/workflow/gemini_engine.go @@ -27,16 +27,10 @@ func NewGeminiEngine() *GeminiEngine { supportsWebFetch: false, supportsWebSearch: false, supportsPlugins: false, - supportsLLMGateway: true, // Gemini supports LLM gateway on port 10003 }, } } -// SupportsLLMGateway returns the LLM gateway port for Gemini engine -func (e *GeminiEngine) SupportsLLMGateway() int { - return constants.GeminiLLMGatewayPort -} - // GetModelEnvVarName returns the native environment variable name that the Gemini CLI uses // for model selection. Setting GEMINI_MODEL is equivalent to passing --model to the CLI. func (e *GeminiEngine) GetModelEnvVarName() string { @@ -233,9 +227,7 @@ func (e *GeminiEngine) GetExecutionSteps(workflowData *WorkflowData, logFile str npmPathSetup := GetNpmBinPathSetup() geminiCommandWithPath := fmt.Sprintf("%s && %s", npmPathSetup, geminiCommand) - // Enable API proxy sidecar if this engine supports LLM gateway - llmGatewayPort := e.SupportsLLMGateway() - usesAPIProxy := llmGatewayPort > 0 + usesAPIProxy := true command = BuildAWFCommand(AWFCommandConfig{ EngineName: "gemini", diff --git a/pkg/workflow/gemini_engine_test.go b/pkg/workflow/gemini_engine_test.go index a4bf6058fa..2d69c6d4b1 100644 --- a/pkg/workflow/gemini_engine_test.go +++ b/pkg/workflow/gemini_engine_test.go @@ -26,7 +26,6 @@ func TestGeminiEngine(t *testing.T) { assert.False(t, engine.SupportsWebFetch(), "Should not support built-in web fetch") assert.False(t, engine.SupportsWebSearch(), "Should not support built-in web search") assert.False(t, engine.SupportsPlugins(), "Should not support plugins") - assert.Equal(t, 10003, engine.SupportsLLMGateway(), "Should support LLM gateway on port 10003") }) t.Run("required secrets", func(t *testing.T) { diff --git a/pkg/workflow/strict_mode_llm_gateway_test.go b/pkg/workflow/strict_mode_llm_gateway_test.go index 2cdd042e6d..08c4f71f82 100644 --- a/pkg/workflow/strict_mode_llm_gateway_test.go +++ b/pkg/workflow/strict_mode_llm_gateway_test.go @@ -5,8 +5,6 @@ package workflow import ( "strings" "testing" - - "github.com/github/gh-aw/pkg/constants" ) // TestValidateStrictFirewall_LLMGatewaySupport tests the LLM gateway validation in strict mode @@ -263,53 +261,6 @@ func TestValidateStrictFirewall_LLMGatewaySupport(t *testing.T) { }) } -// TestSupportsLLMGateway tests the SupportsLLMGateway method for each engine -func TestSupportsLLMGateway(t *testing.T) { - registry := NewEngineRegistry() - - tests := []struct { - engineID string - expectedPort int - description string - }{ - { - engineID: "codex", - expectedPort: constants.CodexLLMGatewayPort, - description: "Codex engine uses dedicated port for LLM gateway", - }, - { - engineID: "claude", - expectedPort: constants.ClaudeLLMGatewayPort, - description: "Claude engine uses dedicated port for LLM gateway", - }, - { - engineID: "copilot", - expectedPort: constants.CopilotLLMGatewayPort, - description: "Copilot engine uses dedicated port for LLM gateway", - }, - { - engineID: "gemini", - expectedPort: constants.GeminiLLMGatewayPort, - description: "Gemini engine uses dedicated port for LLM gateway", - }, - } - - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - engine, err := registry.GetEngine(tt.engineID) - if err != nil { - t.Fatalf("Failed to get engine '%s': %v", tt.engineID, err) - } - - llmGatewayPort := engine.SupportsLLMGateway() - if llmGatewayPort != tt.expectedPort { - t.Errorf("Engine '%s': expected SupportsLLMGateway() = %d, got %d", - tt.engineID, tt.expectedPort, llmGatewayPort) - } - }) - } -} - // TestValidateStrictFirewall_EcosystemSuggestions tests ecosystem suggestions in warning messages func TestValidateStrictFirewall_EcosystemSuggestions(t *testing.T) { t.Run("warns with ecosystem suggestion when individual domain from ecosystem is used", func(t *testing.T) { diff --git a/pkg/workflow/strict_mode_validation.go b/pkg/workflow/strict_mode_validation.go index 373cad4841..a5b9b2db4f 100644 --- a/pkg/workflow/strict_mode_validation.go +++ b/pkg/workflow/strict_mode_validation.go @@ -445,27 +445,19 @@ func (c *Compiler) validateStrictFirewall(engineID string, networkPermissions *N return nil } - // Get the engine instance to check LLM gateway support - agenticEngine, err := c.engineRegistry.GetEngine(engineID) + // Validate that the engine ID exists in the registry + _, err := c.engineRegistry.GetEngine(engineID) if err != nil { strictModeValidationLog.Printf("Failed to get engine: %v", err) return fmt.Errorf("internal error: failed to get engine '%s': %w", engineID, err) } - // Check if engine supports LLM gateway - llmGatewayPort := agenticEngine.SupportsLLMGateway() - strictModeValidationLog.Printf("Engine '%s' LLM gateway port: %d", engineID, llmGatewayPort) - // Check if sandbox.agent: false is set (explicitly disabled) sandboxAgentDisabled := sandboxConfig != nil && sandboxConfig.Agent != nil && sandboxConfig.Agent.Disabled // In strict mode, sandbox.agent: false is not allowed for any engine as it disables the agent sandbox firewall if sandboxAgentDisabled { strictModeValidationLog.Printf("sandbox.agent: false is set, refusing in strict mode") - // For engines without LLM gateway support, provide more specific error message - if llmGatewayPort < 0 { - return fmt.Errorf("strict mode: engine '%s' does not support LLM gateway and requires 'sandbox.agent' to be enabled for security. Remove 'sandbox.agent: false' or set 'strict: false'. See: https://github.github.com/gh-aw/reference/sandbox/", engineID) - } return errors.New("strict mode: 'sandbox.agent: false' is not allowed because it disables the agent sandbox firewall. This removes important security protections. Remove 'sandbox.agent: false' or set 'strict: false' to disable strict mode. See: https://github.github.com/gh-aw/reference/sandbox/") }