From 8d1c269bee9d1909415e46aedeeb9870603d0c32 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Oct 2025 00:54:00 +0000 Subject: [PATCH 1/5] Initial plan From 3f837a0f77a6ce72b8ae0b166f08bc65dcf6fee2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Oct 2025 01:01:54 +0000 Subject: [PATCH 2/5] Remove timeout requirement from strict mode Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- docs/src/content/docs/guides/security.md | 13 ++-- .../src/content/docs/reference/frontmatter.md | 11 ++- pkg/workflow/strict_mode.go | 59 +--------------- pkg/workflow/strict_mode_test.go | 67 ++++++------------- 4 files changed, 34 insertions(+), 116 deletions(-) diff --git a/docs/src/content/docs/guides/security.md b/docs/src/content/docs/guides/security.md index 59d0aee173..dfb3b4b581 100644 --- a/docs/src/content/docs/guides/security.md +++ b/docs/src/content/docs/guides/security.md @@ -93,7 +93,7 @@ network: - "api.example.com" ``` -Strict mode prevents write permissions (`contents:write`, `issues:write`, `pull-requests:write`) and requires explicit network configuration and timeouts. Use `safe-outputs` configuration instead for controlled GitHub API interactions. See [Strict Mode Validation](#strict-mode-validation) for details. +Strict mode prevents write permissions (`contents:write`, `issues:write`, `pull-requests:write`) and requires explicit network configuration. Use `safe-outputs` configuration instead for controlled GitHub API interactions. See [Strict Mode Validation](#strict-mode-validation) for details. ### Human in the Loop @@ -113,7 +113,6 @@ For production workflows, use strict mode to enforce enhanced security and relia ```yaml # Enable strict mode declaratively in frontmatter strict: true -timeout_minutes: 10 permissions: contents: read network: @@ -129,14 +128,12 @@ gh aw compile --strict **Strict mode enforces:** -1. **Timeout Required**: All workflows must specify `timeout_minutes` to prevent runaway executions -2. **Write Permissions Blocked**: Refuses `contents:write`, `issues:write`, and `pull-requests:write` (use `safe-outputs` instead) -3. **Network Configuration Required**: Must explicitly configure network access (cannot rely on defaults) -4. **No Network Wildcards**: Cannot use wildcard `*` in `network.allowed` domains -5. **MCP Network Configuration**: Custom MCP servers with containers must have network configuration +1. **Write Permissions Blocked**: Refuses `contents:write`, `issues:write`, and `pull-requests:write` (use `safe-outputs` instead) +2. **Network Configuration Required**: Must explicitly configure network access (cannot rely on defaults) +3. **No Network Wildcards**: Cannot use wildcard `*` in `network.allowed` domains +4. **MCP Network Configuration**: Custom MCP servers with containers must have network configuration **Benefits:** -- **Cost Control**: Prevents unbounded execution times through mandatory timeouts - **Security**: Minimizes attack surface by blocking write permissions and requiring explicit network access - **Compliance**: Ensures workflows meet organizational security standards - **Auditability**: Clear security requirements make workflows easier to review diff --git a/docs/src/content/docs/reference/frontmatter.md b/docs/src/content/docs/reference/frontmatter.md index 90e289a212..c2f63266f9 100644 --- a/docs/src/content/docs/reference/frontmatter.md +++ b/docs/src/content/docs/reference/frontmatter.md @@ -297,11 +297,10 @@ strict: false When `strict: true`, the workflow must satisfy these requirements: -1. **Timeout Required**: Must specify `timeout_minutes` with a positive integer value to prevent runaway executions -2. **Write Permissions Blocked**: Cannot use `contents: write`, `issues: write`, or `pull-requests: write` permissions (use `safe-outputs` instead for controlled GitHub API interactions) -3. **Network Configuration Required**: Must explicitly configure network access (cannot rely on default behavior) -4. **No Network Wildcards**: Cannot use wildcard `*` in `network.allowed` domains -5. **MCP Network Configuration**: Custom MCP servers with containers must have network configuration +1. **Write Permissions Blocked**: Cannot use `contents: write`, `issues: write`, or `pull-requests: write` permissions (use `safe-outputs` instead for controlled GitHub API interactions) +2. **Network Configuration Required**: Must explicitly configure network access (cannot rely on default behavior) +3. **No Network Wildcards**: Cannot use wildcard `*` in `network.allowed` domains +4. **MCP Network Configuration**: Custom MCP servers with containers must have network configuration **Example Strict Mode Workflow:** @@ -311,7 +310,6 @@ on: push strict: true permissions: contents: read -timeout_minutes: 10 engine: claude network: allowed: @@ -334,7 +332,6 @@ The CLI `--strict` flag takes precedence over frontmatter settings. If the CLI f **Use Cases:** - Production workflows that require enhanced security validation - Workflows with elevated permissions that need extra scrutiny -- Cost-sensitive workflows where timeout enforcement is critical - Workflows that need to comply with security policies ## AI Engine (`engine:`) diff --git a/pkg/workflow/strict_mode.go b/pkg/workflow/strict_mode.go index 6e81d67e8d..bdf0521e98 100644 --- a/pkg/workflow/strict_mode.go +++ b/pkg/workflow/strict_mode.go @@ -10,22 +10,17 @@ func (c *Compiler) validateStrictMode(frontmatter map[string]any, networkPermiss return nil } - // 1. Require timeout_minutes - if err := c.validateStrictTimeout(frontmatter); err != nil { - return err - } - - // 2. Refuse write permissions + // 1. Refuse write permissions if err := c.validateStrictPermissions(frontmatter); err != nil { return err } - // 3. Require network configuration and refuse "*" wildcard + // 2. Require network configuration and refuse "*" wildcard if err := c.validateStrictNetwork(networkPermissions); err != nil { return err } - // 4. Require network configuration on custom MCP servers + // 3. Require network configuration on custom MCP servers if err := c.validateStrictMCPNetwork(frontmatter); err != nil { return err } @@ -33,54 +28,6 @@ func (c *Compiler) validateStrictMode(frontmatter map[string]any, networkPermiss return nil } -// validateStrictTimeout ensures timeout_minutes is specified in strict mode -func (c *Compiler) validateStrictTimeout(frontmatter map[string]any) error { - timeoutValue, exists := frontmatter["timeout_minutes"] - if !exists { - return fmt.Errorf("strict mode: 'timeout_minutes' is required in workflow frontmatter") - } - - // Validate it's a positive integer (handle various numeric types) - switch v := timeoutValue.(type) { - case int: - if v <= 0 { - return fmt.Errorf("strict mode: 'timeout_minutes' must be a positive integer, got %d", v) - } - case int32: - if v <= 0 { - return fmt.Errorf("strict mode: 'timeout_minutes' must be a positive integer, got %d", v) - } - case int64: - if v <= 0 { - return fmt.Errorf("strict mode: 'timeout_minutes' must be a positive integer, got %d", v) - } - case uint: - if v == 0 { - return fmt.Errorf("strict mode: 'timeout_minutes' must be a positive integer, got %d", v) - } - case uint32: - if v == 0 { - return fmt.Errorf("strict mode: 'timeout_minutes' must be a positive integer, got %d", v) - } - case uint64: - if v == 0 { - return fmt.Errorf("strict mode: 'timeout_minutes' must be a positive integer, got %d", v) - } - case float64: - if v <= 0 { - return fmt.Errorf("strict mode: 'timeout_minutes' must be a positive integer, got %f", v) - } - case float32: - if v <= 0 { - return fmt.Errorf("strict mode: 'timeout_minutes' must be a positive integer, got %f", v) - } - default: - return fmt.Errorf("strict mode: 'timeout_minutes' must be an integer, got type %T", timeoutValue) - } - - return nil -} - // validateStrictPermissions refuses write permissions in strict mode func (c *Compiler) validateStrictPermissions(frontmatter map[string]any) error { permissionsValue, exists := frontmatter["permissions"] diff --git a/pkg/workflow/strict_mode_test.go b/pkg/workflow/strict_mode_test.go index e4ecc42387..1cb7ebbacf 100644 --- a/pkg/workflow/strict_mode_test.go +++ b/pkg/workflow/strict_mode_test.go @@ -15,58 +15,35 @@ func TestStrictModeTimeout(t *testing.T) { errorMsg string }{ { - name: "valid timeout in strict mode", + name: "timeout not required in strict mode", content: `--- on: push permissions: contents: read -timeout_minutes: 10 engine: claude +network: + allowed: + - "api.example.com" --- # Test Workflow`, expectError: false, }, { - name: "missing timeout in strict mode", - content: `--- -on: push -permissions: - contents: read -engine: claude ---- - -# Test Workflow`, - expectError: true, - errorMsg: "strict mode: 'timeout_minutes' is required", - }, - { - name: "zero timeout in strict mode", + name: "timeout still valid in strict mode when specified", content: `--- on: push permissions: contents: read -timeout_minutes: 0 -engine: claude ---- - -# Test Workflow`, - expectError: true, - errorMsg: "strict mode: 'timeout_minutes' must be a positive integer", - }, - { - name: "negative timeout in strict mode", - content: `--- -on: push -permissions: - contents: read -timeout_minutes: -5 +timeout_minutes: 10 engine: claude +network: + allowed: + - "api.example.com" --- # Test Workflow`, - expectError: true, - errorMsg: "strict mode: 'timeout_minutes' must be a positive integer", + expectError: false, }, } @@ -474,11 +451,13 @@ strict: true permissions: contents: read engine: claude +network: + allowed: + - "api.example.com" --- # Test Workflow`, - expectError: true, - errorMsg: "strict mode: 'timeout_minutes' is required", + expectError: false, }, { name: "strict: false in frontmatter does not enable strict mode", @@ -581,11 +560,11 @@ engine: claude compiler.SetStrictMode(true) // CLI flag sets strict mode err = compiler.CompileWorkflow(testFile) - // Should fail because CLI flag enforces strict mode despite frontmatter saying false + // Should fail because CLI flag enforces strict mode and write permission is not allowed if err == nil { t.Error("Expected compilation to fail with CLI --strict flag, but it succeeded") - } else if !strings.Contains(err.Error(), "timeout_minutes") { - t.Errorf("Expected timeout error, got: %v", err) + } else if !strings.Contains(err.Error(), "write permission") { + t.Errorf("Expected write permission error, got: %v", err) } } @@ -597,7 +576,7 @@ func TestStrictModeIsolation(t *testing.T) { } defer os.RemoveAll(tmpDir) - // First workflow with strict: true (missing timeout_minutes - should fail) + // First workflow with strict: true (should succeed now without timeout) strictWorkflow := `--- on: push strict: true @@ -634,15 +613,13 @@ engine: claude compiler := NewCompiler(false, "", "") // Do NOT set strict mode via CLI - let frontmatter control it - // Compile strict workflow first - should fail + // Compile strict workflow first - should succeed now err = compiler.CompileWorkflow(strictFile) - if err == nil { - t.Error("Expected strict workflow to fail due to missing timeout_minutes, but it succeeded") - } else if !strings.Contains(err.Error(), "timeout_minutes") { - t.Errorf("Expected timeout_minutes error for strict workflow, got: %v", err) + if err != nil { + t.Errorf("Expected strict workflow to succeed, but it failed: %v", err) } - // Compile non-strict workflow second - should succeed + // Compile non-strict workflow second - should also succeed // This tests that strict mode from first workflow doesn't leak err = compiler.CompileWorkflow(nonStrictFile) if err != nil { From 4c3f3d13d8d5c1adf0c6837efa5703ec96e8d644 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Oct 2025 03:18:35 +0000 Subject: [PATCH 3/5] Set default timeout to 20 minutes for agentic workflows Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/artifacts-summary.lock.yml | 2 +- .github/workflows/audit-workflows.lock.yml | 2 +- .github/workflows/brave.lock.yml | 2 +- .github/workflows/changeset-generator.lock.yml | 2 +- .github/workflows/ci-doctor.lock.yml | 2 +- .github/workflows/cli-version-checker.lock.yml | 2 +- .github/workflows/go-pattern-detector.lock.yml | 2 +- .github/workflows/pdf-summary.lock.yml | 2 +- .github/workflows/poem-bot.lock.yml | 2 +- .github/workflows/scout.lock.yml | 2 +- .github/workflows/smoke-claude.lock.yml | 2 +- .github/workflows/smoke-copilot.lock.yml | 2 +- .github/workflows/technical-doc-writer.lock.yml | 2 +- .github/workflows/tidy.lock.yml | 2 +- docs/src/content/docs/reference/frontmatter.md | 2 +- pkg/workflow/claude_engine.go | 2 +- pkg/workflow/copilot_engine.go | 2 +- pkg/workflow/tools.go | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index c77181ef36..07e20a4a18 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -2973,7 +2973,7 @@ jobs: run: npm install -g @github/copilot@0.0.337 - name: Execute GitHub Copilot CLI id: agentic_execution - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail COPILOT_CLI_INSTRUCTION=$(cat /tmp/gh-aw/aw-prompts/prompt.txt) diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index c13f9cc503..cbd7613d92 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -3106,7 +3106,7 @@ jobs: # - Read # - Task # - TodoWrite - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail # Execute Claude Code CLI with prompt from file diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 6fa6c12ef0..757fbd7b30 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -3528,7 +3528,7 @@ jobs: run: npm install -g @github/copilot@0.0.337 - name: Execute GitHub Copilot CLI id: agentic_execution - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail COPILOT_CLI_INSTRUCTION=$(cat /tmp/gh-aw/aw-prompts/prompt.txt) diff --git a/.github/workflows/changeset-generator.lock.yml b/.github/workflows/changeset-generator.lock.yml index 6616cb0340..d4d4c35cd2 100644 --- a/.github/workflows/changeset-generator.lock.yml +++ b/.github/workflows/changeset-generator.lock.yml @@ -3192,7 +3192,7 @@ jobs: # - Read # - Task # - TodoWrite - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail # Execute Claude Code CLI with prompt from file diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index 87aab8f657..f1bfc3663f 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -3067,7 +3067,7 @@ jobs: run: npm install -g @github/copilot@0.0.337 - name: Execute GitHub Copilot CLI id: agentic_execution - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail COPILOT_CLI_INSTRUCTION=$(cat /tmp/gh-aw/aw-prompts/prompt.txt) diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index 45ad0af892..8a37c4ebe6 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -2940,7 +2940,7 @@ jobs: # - Read # - Task # - TodoWrite - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail # Execute Claude Code CLI with prompt from file diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index f557f3fd74..1339869de7 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -2806,7 +2806,7 @@ jobs: # - Read # - Task # - TodoWrite - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail # Execute Claude Code CLI with prompt from file diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index 60a6ab4a09..01959512d2 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -3487,7 +3487,7 @@ jobs: run: npm install -g @github/copilot@0.0.337 - name: Execute GitHub Copilot CLI id: agentic_execution - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail COPILOT_CLI_INSTRUCTION=$(cat /tmp/gh-aw/aw-prompts/prompt.txt) diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index 59639ab40a..0d6b5ac6e6 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -3557,7 +3557,7 @@ jobs: run: npm install -g @github/copilot@0.0.337 - name: Execute GitHub Copilot CLI id: agentic_execution - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail COPILOT_CLI_INSTRUCTION=$(cat /tmp/gh-aw/aw-prompts/prompt.txt) diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index d105677322..9b1e19ce90 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -3821,7 +3821,7 @@ jobs: run: npm install -g @github/copilot@0.0.337 - name: Execute GitHub Copilot CLI id: agentic_execution - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail COPILOT_CLI_INSTRUCTION=$(cat /tmp/gh-aw/aw-prompts/prompt.txt) diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index a2663cd1d0..d7210e82c3 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -2649,7 +2649,7 @@ jobs: # - Read # - Task # - TodoWrite - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail # Execute Claude Code CLI with prompt from file diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 1d96c04e46..f233e5711f 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -2901,7 +2901,7 @@ jobs: run: npm install -g @github/copilot@0.0.337 - name: Execute GitHub Copilot CLI id: agentic_execution - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail COPILOT_CLI_INSTRUCTION=$(cat /tmp/gh-aw/aw-prompts/prompt.txt) diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 52dc3aa1a2..e2744f5050 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -3018,7 +3018,7 @@ jobs: # - Read # - Task # - TodoWrite - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail # Execute Claude Code CLI with prompt from file diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index f0ea69f6ab..f2fd262f51 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -3321,7 +3321,7 @@ jobs: run: npm install -g @github/copilot@0.0.337 - name: Execute GitHub Copilot CLI id: agentic_execution - timeout-minutes: 5 + timeout-minutes: 20 run: | set -o pipefail COPILOT_CLI_INSTRUCTION=$(cat /tmp/gh-aw/aw-prompts/prompt.txt) diff --git a/docs/src/content/docs/reference/frontmatter.md b/docs/src/content/docs/reference/frontmatter.md index c2f63266f9..fb4ba34bf6 100644 --- a/docs/src/content/docs/reference/frontmatter.md +++ b/docs/src/content/docs/reference/frontmatter.md @@ -592,7 +592,7 @@ Standard GitHub Actions properties: ```yaml run-name: "Custom workflow run name" # Defaults to workflow name runs-on: ubuntu-latest # Defaults to ubuntu-latest -timeout_minutes: 30 # Defaults to 15 minutes +timeout_minutes: 30 # Defaults to 20 minutes ``` ## Concurrency Control (`concurrency:`) diff --git a/pkg/workflow/claude_engine.go b/pkg/workflow/claude_engine.go index e0bb958ca8..9a91e8efc3 100644 --- a/pkg/workflow/claude_engine.go +++ b/pkg/workflow/claude_engine.go @@ -163,7 +163,7 @@ func (e *ClaudeEngine) GetExecutionSteps(workflowData *WorkflowData, logFile str if workflowData.TimeoutMinutes != "" { stepLines = append(stepLines, fmt.Sprintf(" timeout-minutes: %s", strings.TrimPrefix(workflowData.TimeoutMinutes, "timeout_minutes: "))) } else { - stepLines = append(stepLines, " timeout-minutes: 5") // Default timeout + stepLines = append(stepLines, " timeout-minutes: 20") // Default timeout for agentic workflows } // Build the run command diff --git a/pkg/workflow/copilot_engine.go b/pkg/workflow/copilot_engine.go index 67587345ff..f7935e6f94 100644 --- a/pkg/workflow/copilot_engine.go +++ b/pkg/workflow/copilot_engine.go @@ -168,7 +168,7 @@ copilot %s 2>&1 | tee %s`, shellJoinArgs(copilotArgs), logFile) if workflowData.TimeoutMinutes != "" { stepLines = append(stepLines, fmt.Sprintf(" timeout-minutes: %s", strings.TrimPrefix(workflowData.TimeoutMinutes, "timeout_minutes: "))) } else { - stepLines = append(stepLines, " timeout-minutes: 5") // Default timeout + stepLines = append(stepLines, " timeout-minutes: 20") // Default timeout for agentic workflows } stepLines = append(stepLines, " run: |") diff --git a/pkg/workflow/tools.go b/pkg/workflow/tools.go index 5d74ffdf7a..3e4e4e1f03 100644 --- a/pkg/workflow/tools.go +++ b/pkg/workflow/tools.go @@ -127,7 +127,7 @@ func (c *Compiler) applyDefaults(data *WorkflowData, markdownPath string) { } if data.TimeoutMinutes == "" { - data.TimeoutMinutes = `timeout_minutes: 5` + data.TimeoutMinutes = `timeout_minutes: 20` } if data.RunsOn == "" { From ef5c21f4ba2c3068272e94fe5c454d124b266327 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Oct 2025 03:29:33 +0000 Subject: [PATCH 4/5] Move default timeout to constant in constants.go Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/constants/constants.go | 3 +++ pkg/workflow/claude_engine.go | 2 +- pkg/workflow/copilot_engine.go | 2 +- pkg/workflow/tools.go | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 41026e3bd2..1e174e4fcc 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -44,6 +44,9 @@ const DefaultElixirVersion = "1.17" // DefaultHaskellVersion is the default version of GHC for runtime setup const DefaultHaskellVersion = "9.10" +// DefaultAgenticWorkflowTimeoutMinutes is the default timeout for agentic workflow execution in minutes +const DefaultAgenticWorkflowTimeoutMinutes = 20 + // DefaultAllowedDomains defines the default localhost domains with port variations // that are always allowed for Playwright browser automation var DefaultAllowedDomains = []string{"localhost", "localhost:*", "127.0.0.1", "127.0.0.1:*"} diff --git a/pkg/workflow/claude_engine.go b/pkg/workflow/claude_engine.go index 9a91e8efc3..120281d2a5 100644 --- a/pkg/workflow/claude_engine.go +++ b/pkg/workflow/claude_engine.go @@ -163,7 +163,7 @@ func (e *ClaudeEngine) GetExecutionSteps(workflowData *WorkflowData, logFile str if workflowData.TimeoutMinutes != "" { stepLines = append(stepLines, fmt.Sprintf(" timeout-minutes: %s", strings.TrimPrefix(workflowData.TimeoutMinutes, "timeout_minutes: "))) } else { - stepLines = append(stepLines, " timeout-minutes: 20") // Default timeout for agentic workflows + stepLines = append(stepLines, fmt.Sprintf(" timeout-minutes: %d", constants.DefaultAgenticWorkflowTimeoutMinutes)) // Default timeout for agentic workflows } // Build the run command diff --git a/pkg/workflow/copilot_engine.go b/pkg/workflow/copilot_engine.go index f7935e6f94..b07f9c2149 100644 --- a/pkg/workflow/copilot_engine.go +++ b/pkg/workflow/copilot_engine.go @@ -168,7 +168,7 @@ copilot %s 2>&1 | tee %s`, shellJoinArgs(copilotArgs), logFile) if workflowData.TimeoutMinutes != "" { stepLines = append(stepLines, fmt.Sprintf(" timeout-minutes: %s", strings.TrimPrefix(workflowData.TimeoutMinutes, "timeout_minutes: "))) } else { - stepLines = append(stepLines, " timeout-minutes: 20") // Default timeout for agentic workflows + stepLines = append(stepLines, fmt.Sprintf(" timeout-minutes: %d", constants.DefaultAgenticWorkflowTimeoutMinutes)) // Default timeout for agentic workflows } stepLines = append(stepLines, " run: |") diff --git a/pkg/workflow/tools.go b/pkg/workflow/tools.go index 3e4e4e1f03..9cc1fcd9ad 100644 --- a/pkg/workflow/tools.go +++ b/pkg/workflow/tools.go @@ -6,6 +6,7 @@ import ( "os" "strings" + "github.com/githubnext/gh-aw/pkg/constants" "github.com/githubnext/gh-aw/pkg/parser" "github.com/goccy/go-yaml" ) @@ -127,7 +128,7 @@ func (c *Compiler) applyDefaults(data *WorkflowData, markdownPath string) { } if data.TimeoutMinutes == "" { - data.TimeoutMinutes = `timeout_minutes: 20` + data.TimeoutMinutes = fmt.Sprintf("timeout_minutes: %d", constants.DefaultAgenticWorkflowTimeoutMinutes) } if data.RunsOn == "" { From a127bba52652c5174c392a81c4d1fc71e986dac9 Mon Sep 17 00:00:00 2001 From: Changeset Generator Date: Fri, 10 Oct 2025 03:30:44 +0000 Subject: [PATCH 5/5] Add changeset for strict mode timeout requirement removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .changeset/minor-remove-strict-mode-timeout-requirement.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/minor-remove-strict-mode-timeout-requirement.md diff --git a/.changeset/minor-remove-strict-mode-timeout-requirement.md b/.changeset/minor-remove-strict-mode-timeout-requirement.md new file mode 100644 index 0000000000..2cbaa86bcb --- /dev/null +++ b/.changeset/minor-remove-strict-mode-timeout-requirement.md @@ -0,0 +1,7 @@ +--- +"githubnext/gh-aw": minor +--- + +Remove timeout requirement for strict mode and set default timeout to 20 minutes + +This change makes strict mode more flexible by removing the requirement to specify `timeout_minutes`. Workflows can still set a timeout for cost control, but it's no longer mandatory for enabling strict mode's security features. The default timeout for agentic workflows has also been increased from 5 to 20 minutes to better accommodate typical workflow execution times.