GetExecutionSteps returns the GitHub Actions steps for executing Codex
(workflowData *WorkflowData, logFile string)
| 175 | |
| 176 | // GetExecutionSteps returns the GitHub Actions steps for executing Codex |
| 177 | func (e *CodexEngine) GetExecutionSteps(workflowData *WorkflowData, logFile string) []GitHubActionStep { |
| 178 | modelConfigured := workflowData.EngineConfig != nil && workflowData.EngineConfig.Model != "" |
| 179 | firewallEnabled := isFirewallEnabled(workflowData) |
| 180 | codexEngineLog.Printf("Building Codex execution steps: workflow=%s, modelConfigured=%v, firewall=%v", |
| 181 | workflowData.Name, modelConfigured, firewallEnabled) |
| 182 | |
| 183 | var steps []GitHubActionStep |
| 184 | |
| 185 | // Codex does not support a native model environment variable, so model selection |
| 186 | // always uses GH_AW_MODEL_AGENT_CODEX or GH_AW_MODEL_DETECTION_CODEX with shell expansion |
| 187 | // via the --model flag. This also correctly handles GitHub Actions expressions like ${{ inputs.model }}. |
| 188 | // Note: Codex also supports config-layer model selection (config key `model`, including `-c model="..."`), |
| 189 | // but `--model` is a direct CLI flag and avoids TOML quoting/parsing edge cases in automation. |
| 190 | isDetectionJob := workflowData.SafeOutputs == nil |
| 191 | var modelEnvVar string |
| 192 | if isDetectionJob { |
| 193 | modelEnvVar = constants.EnvVarModelDetectionCodex |
| 194 | } else { |
| 195 | modelEnvVar = constants.EnvVarModelAgentCodex |
| 196 | } |
| 197 | modelParam := fmt.Sprintf(`${%s:+ --model "$%s"}`, modelEnvVar, modelEnvVar) |
| 198 | |
| 199 | // Build search parameter: disable web search by default, enable only if web-search tool is present. |
| 200 | // Codex enables web search by default, so we must explicitly set web_search="disabled" to disable it. |
| 201 | // The --no-search flag does not exist; use the -c web_search="disabled" config option instead. |
| 202 | // See https://developers.openai.com/codex/cli/features#web-search |
| 203 | // Leading space is intentional: these params are concatenated directly and need their own separator. |
| 204 | webSearchParam := ` -c web_search="disabled"` |
| 205 | if workflowData.ParsedTools != nil && workflowData.ParsedTools.WebSearch != nil { |
| 206 | // Web search is enabled by default in Codex; no extra flag needed. |
| 207 | webSearchParam = "" |
| 208 | } |
| 209 | |
| 210 | // Build fetch parameter: enforce AWF default-deny for fetch unless web-fetch tool is present. |
| 211 | // Codex enables fetch by default, so this code explicitly sets fetch="disabled" unless web-fetch is configured. |
| 212 | // Leading space is intentional: these params are concatenated directly and need their own separator. |
| 213 | webFetchParam := ` -c fetch="disabled"` |
| 214 | if workflowData.ParsedTools != nil && workflowData.ParsedTools.WebFetch != nil { |
| 215 | // When web-fetch is configured, omit override so Codex default fetch behavior remains enabled. |
| 216 | webFetchParam = "" |
| 217 | } |
| 218 | |
| 219 | // See https://github.com/github/gh-aw/issues/892 |
| 220 | // In AWF mode we bypass Codex approvals/sandboxing because AWF provides the sandbox layer. |
| 221 | // Outside AWF, keep Codex sandboxing enabled and disable approvals for non-interactive execution. |
| 222 | executionPolicyParam := ` --sandbox workspace-write --skip-git-repo-check -c approval_policy="never" ` |
| 223 | if firewallEnabled { |
| 224 | executionPolicyParam = " --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check " |
| 225 | } |
| 226 | |
| 227 | // Build custom args parameter if specified in engineConfig |
| 228 | var customArgsParam string |
| 229 | if workflowData.EngineConfig != nil && len(workflowData.EngineConfig.Args) > 0 { |
| 230 | var customArgsParamSb strings.Builder |
| 231 | for _, arg := range workflowData.EngineConfig.Args { |
| 232 | customArgsParamSb.WriteString(arg + " ") |
| 233 | } |
| 234 | customArgsParam += customArgsParamSb.String() |